﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using Common.Utilities;

namespace Workflows.Components.TextMining.EnumerationObjects
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class ExtractionRule
    {
        #region consts
        public const double Min_Line_Spacing_Over_Font_Size = 1;
        public const string ESNAP_TAG = "ESNAP Report";
        public const double MIN_COLHEADER_MATCH_SCORE = 0.70;
        public const double Min_TableHeader_Match_Score = 0.9;
        public const int ColumnHeaderSlidingWindwSize = 15;
        public const int ColumnHeaderSlidingWindowStep = 5;
        public const int AdjustColumnHeaderWidthFromTableRowCount = 5;
        public const bool ColHeaderUseRegexMatch = false;
        public const bool TableHeaderUseRegexMatch = false;
        #endregion

        #region prop
        private string _TableHeader;
        /// <summary></summary>
        public string TableHeader
        {
            get
            {
                return this._TableHeader;
            }
            set
            {
                this._TableHeader = value;
            }
        }

        private string _TableFooter;
        /// <summary></summary>
        public string TableFooter
        {
            get
            {
                return this._TableFooter;
            }
            set
            {
                this._TableFooter = value;
            }
        }

        private Dictionary<int, List<PdfTableColumnHeaderMapping>> _ColHeaderOptions;
        /// <summary></summary>
        public Dictionary<int, List<PdfTableColumnHeaderMapping>> ColHeaderOptions
        {
            get { return _ColHeaderOptions; }
            set { _ColHeaderOptions = value; }
        }
        #endregion

        #region methods
        /// <summary>
        /// 
        /// </summary>
        public static ExtractionRule DefaultRule
        {
            get
            {
                Dictionary<string, string[]> tgtSrcFieldMappings = new Dictionary<string, string[]>();
                tgtSrcFieldMappings.Add("PersonFullName", new string[4] {"Name", "Name", "Name", "Name"});
                tgtSrcFieldMappings.Add("Degree", new string[4] {"Degree(s)", "Degree(s)", "Degree(s)", "Degree(s)"});
                tgtSrcFieldMappings.Add("SSN", new string[4] {"SSN", "SSN", "SSN", "SSN"});
                tgtSrcFieldMappings.Add("Role",
                                        new string[4]
                                            {"Role on Project", "Role on Project", "Role on Project", "Role on Project"});
                tgtSrcFieldMappings.Add("DOB", new string[4] {"Date of Birth", "Date of Birth", "", ""});
                tgtSrcFieldMappings.Add("PercentEffort", new string[4] {"", "Annual % Effort", "", "Annual % Effort"});
                tgtSrcFieldMappings.Add("CalendarEffort", new string[4] {"Cal", "", "Cal", ""});
                tgtSrcFieldMappings.Add("AcademicEffort", new string[4] {"Acad", "", "Acad", ""});
                tgtSrcFieldMappings.Add("SummerEffort", new string[4] {"Sum", "", "Sum", ""});

                ExtractionRule rule = new ExtractionRule();
                rule.TableHeader = "Personnel Report";
                rule.TableFooter = string.Empty;

                rule.ColHeaderOptions = new Dictionary<int, List<PdfTableColumnHeaderMapping>>();


                List<PdfTableColumnHeaderMapping> colMaps1 = new List<PdfTableColumnHeaderMapping>();
                List<PdfTableColumnHeaderMapping> colMaps2 = new List<PdfTableColumnHeaderMapping>();
                List<PdfTableColumnHeaderMapping> colMaps3 = new List<PdfTableColumnHeaderMapping>();
                List<PdfTableColumnHeaderMapping> colMaps4 = new List<PdfTableColumnHeaderMapping>();
                string[] fieldNamesInDB = new string[tgtSrcFieldMappings.Count];
                tgtSrcFieldMappings.Keys.CopyTo(fieldNamesInDB, 0);
                for (int i = 0; i < fieldNamesInDB.Length; i++)
                {
                    string fieldNameInDB = fieldNamesInDB[i];
                    PdfTableColumnHeaderMapping colHeaderMap1 = new PdfTableColumnHeaderMapping();
                    colHeaderMap1.FieldNameInDB = fieldNameInDB;
                    colHeaderMap1.FieldNameInPdf = tgtSrcFieldMappings[fieldNameInDB][0];
                    colHeaderMap1.FieldOrderInPdf = i + 1;
                    if (!string.IsNullOrEmpty(colHeaderMap1.FieldNameInPdf))
                    {
                        colMaps1.Add(colHeaderMap1);
                    }

                    PdfTableColumnHeaderMapping colHeaderMap2 = new PdfTableColumnHeaderMapping();
                    colHeaderMap2.FieldNameInDB = fieldNameInDB;
                    colHeaderMap2.FieldNameInPdf = tgtSrcFieldMappings[fieldNameInDB][1];
                    colHeaderMap2.FieldOrderInPdf = i + 1;
                    if (!string.IsNullOrEmpty(colHeaderMap2.FieldNameInPdf))
                    {
                        colMaps2.Add(colHeaderMap2);
                    }

                    PdfTableColumnHeaderMapping colHeaderMap3 = new PdfTableColumnHeaderMapping();
                    colHeaderMap3.FieldNameInDB = fieldNameInDB;
                    colHeaderMap3.FieldNameInPdf = tgtSrcFieldMappings[fieldNameInDB][2];
                    colHeaderMap3.FieldOrderInPdf = i + 1;
                    if (!string.IsNullOrEmpty(colHeaderMap3.FieldNameInPdf))
                    {
                        colMaps3.Add(colHeaderMap3);
                    }

                    PdfTableColumnHeaderMapping colHeaderMap4 = new PdfTableColumnHeaderMapping();
                    colHeaderMap4.FieldNameInDB = fieldNameInDB;
                    colHeaderMap4.FieldNameInPdf = tgtSrcFieldMappings[fieldNameInDB][3];
                    colHeaderMap4.FieldOrderInPdf = i + 1;
                    if (!string.IsNullOrEmpty(colHeaderMap4.FieldNameInPdf))
                    {
                        colMaps4.Add(colHeaderMap4);
                    }
                }
                rule.ColHeaderOptions.Add(1, colMaps1);
                rule.ColHeaderOptions.Add(2, colMaps2);
                rule.ColHeaderOptions.Add(3, colMaps3);
                rule.ColHeaderOptions.Add(4, colMaps4);

                return rule;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static ExtractionRule ReadRuleFromXmlFile()
        {
            string appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            appDataFolder = Path.Combine(appDataFolder, "Workflow Data");
            if(!Directory.Exists(appDataFolder))
            {
                Directory.CreateDirectory(appDataFolder);
            }
            string xmlFilePath = Path.Combine(appDataFolder, "ExtractionRule.xml");
            XmlDocument xDoc=new XmlDocument();
            if(File.Exists(xmlFilePath))
            {
                xDoc.Load(xmlFilePath);
                ExtractionRule rule=new ExtractionRule();
                XmlNode root = xDoc.DocumentElement;
                rule.TableHeader = XmlDataUtil.GetAttributeValue(root, "TableHeader", "Personnel Report");
                rule.TableFooter = XmlDataUtil.GetAttributeValue(root, "TableFooter", "");
                XmlNodeList appOrderNodes = root.SelectNodes("ApplyOrders/ApplyOrder");
                if(appOrderNodes !=null && appOrderNodes.Count>0)
                {
                    rule.ColHeaderOptions=new Dictionary<int, List<PdfTableColumnHeaderMapping>>();
                    foreach(XmlNode appOrderNode in appOrderNodes)
                    {
                        int applyOrder = int.Parse(XmlDataUtil.GetAttributeValue(appOrderNode, "ApplyOrder", "1"));
                        List<PdfTableColumnHeaderMapping> colHeaderMaps=new List<PdfTableColumnHeaderMapping>();
                        XmlNodeList colHeaderOpNodes = appOrderNode.SelectNodes("TableColumnHeaderMapping");
                        if(colHeaderOpNodes !=null && colHeaderOpNodes.Count>0)
                        {
                            foreach(XmlNode colHeaderNode in colHeaderOpNodes)
                            {
                                PdfTableColumnHeaderMapping colHeaderMap=new PdfTableColumnHeaderMapping();
                                colHeaderMap.FieldNameInDB =
                                    colHeaderNode.Attributes.GetNamedItem("FieldNameInDB").Value;
                                colHeaderMap.FieldNameInPdf =
                                    colHeaderNode.Attributes.GetNamedItem("FieldNameInPDF").Value;
                                colHeaderMap.FieldOrderInPdf =
                                    int.Parse(colHeaderNode.Attributes.GetNamedItem("FieldOrderInPDF").Value);
                                colHeaderMaps.Add(colHeaderMap);
                            }
                        }
                        rule.ColHeaderOptions.Add(applyOrder,colHeaderMaps);
                    }
                }
                return rule;
            }
            else
            {
                return ExtractionRule.DefaultRule;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="rule"></param>
        public static void SaveRule(ExtractionRule rule)
        {
            string appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            appDataFolder = Path.Combine(appDataFolder, "Workflow Data");
            if (!Directory.Exists(appDataFolder))
            {
                Directory.CreateDirectory(appDataFolder);
            }
            string xmlFilePath = Path.Combine(appDataFolder, "ExtractionRule.xml");
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<ExtractionRule></ExtractionRule>");
            XmlNode root = xDoc.DocumentElement;
            root.RemoveAll();
            XmlDataUtil.UpdateAttribute(ref xDoc,root,"TableHeader", rule.TableHeader);
            XmlDataUtil.UpdateAttribute(ref xDoc,root,"TableFooter",rule.TableFooter);
            XmlNode tblHeaderOpRootNode = XmlDataUtil.AddElement(ref xDoc, root, "ApplyOrders");
            foreach(int applyOrder in rule.ColHeaderOptions.Keys)
            {
                XmlNode applyOrderNode = XmlDataUtil.AddElement(ref xDoc, tblHeaderOpRootNode, "ApplyOrder");
                XmlDataUtil.UpdateAttribute(ref xDoc,applyOrderNode,"ApplyOrder",applyOrder.ToString());
                List<PdfTableColumnHeaderMapping> tblHeaderMaps = rule.ColHeaderOptions[applyOrder];
                foreach (PdfTableColumnHeaderMapping colMap in tblHeaderMaps)
                {
                    XmlNode tblHeaderNode = XmlDataUtil.AddElement(ref xDoc, applyOrderNode, "TableColumnHeaderMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc,tblHeaderNode,"FieldNameInDB",colMap.FieldNameInDB);
                    XmlDataUtil.UpdateAttribute(ref xDoc,tblHeaderNode,"FieldNameInPDF",colMap.FieldNameInPdf);
                    XmlDataUtil.UpdateAttribute(ref xDoc,tblHeaderNode,"FieldOrderInPDF",colMap.FieldOrderInPdf.ToString());
                }
            }
            xDoc.Save(xmlFilePath);
        }
        #endregion
    }

    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public struct PdfTableColumnHeaderMapping : IComparable
    {
        public string FieldNameInDB;
        public string FieldNameInPdf;
        public int FieldOrderInPdf;

        public int CompareTo(object obj)
        {
            if (obj.GetType() == typeof(PdfTableColumnHeaderMapping))
            {
                PdfTableColumnHeaderMapping fm = (PdfTableColumnHeaderMapping)obj;
                return this.FieldOrderInPdf.CompareTo(fm.FieldOrderInPdf);
            }
            else
                return 0;
        }
    }
}
